#include <cmath>
#include "Sampler.h"

Sampler::Sampler( const unsigned int rings, const unsigned int *ringsRadius, const unsigned int *samplesPerRing )
: pattern(0), maxRadius(0)
{
	for( unsigned int i = 0 ; i<rings ; i++ )
	{
		maxRadius = ( maxRadius < ringsRadius[i] ) ? ringsRadius[i] : maxRadius;

		double intervalle = (2*M_PI) / samplesPerRing[i];
		for( unsigned int j = 0 ; j<samplesPerRing[i] ; j++)
		{
			// Conversion coordonnées polaires->cartésiennes
			double x = ringsRadius[i]*cos(j*intervalle);
			double y = ringsRadius[i]*sin(j*intervalle);

			// Ajout de la paire de coordonnées relatives au point central
			pattern.push_back( pair<int, int>( (int) x, (int) y ) );
		}
	}
}


void Sampler::operator()( const CVGreyc::NDArray::CArray<double> &data, const unsigned int centerX, const unsigned int centerY, CVGreyc::NDArray::CArray<double> &result ) const throw(Sampler::InvalidIndex)
{
	if( (centerX + maxRadius) > data.shape(0) or (centerX + maxRadius) < 0 or
	    (centerY + maxRadius) > data.shape(1) or (centerY + maxRadius) < 0)
	{
		throw InvalidIndex();
	}

	for( vector< pair<int, int> >::size_type i = 0 ; i < pattern.size() ; i++ )
	{
		result(i) = data( centerX + pattern[i].first , centerY + pattern[i].second );
	}
}

void Sampler::operator()( const CVGreyc::NDArray::CArray<double> &data, const CVGreyc::NDArray::CArray<unsigned int> &xy_, CVGreyc::NDArray::CArray<double> &result ) const throw(Sampler::InvalidIndex)
{
	for( unsigned int i=0 ; i<xy_.shape(0) ; i++ )
	{
		if( (xy_(i,0) + maxRadius) > data.shape(0) or (xy_(i,0) + maxRadius) < 0 or
		    (xy_(i,1) + maxRadius) > data.shape(1) or (xy_(i,1) + maxRadius) < 0)
		{
			throw InvalidIndex();
		}

		for( vector< pair<int, int> >::size_type j = 0 ; j < pattern.size() ; j++ )
		{
			result(i,j) = data( xy_(i,0) + pattern[j].first , xy_(i,1) + pattern[j].second );
		}
	}
}

 void Sampler::operator()( const CVGreyc::NDArray::CArray<double> &data, CVGreyc::NDArray::CArray<double> &result ) const
{
	unsigned int outX = 0;
	unsigned int outY = 0;

	for( unsigned int x = maxRadius ; x< (data.shape(0)-maxRadius) ; x++ )
	{
		for( unsigned int y = maxRadius ; y<(data.shape(1)-maxRadius) ; y++ )
		{
			for( vector< pair<int, int> >::size_type z = 0 ; z < pattern.size() ; z++ )
			{
				result(outX, outY, z) = data( (x + pattern[z].first) , (y + pattern[z].second) );
			}
			outY++;
		}
		outY = 0;
		outX++;
	}
}

unsigned int Sampler::getXRes( const CVGreyc::NDArray::CArray<double> &data ) const
{
	return data.shape(0) - ( 2*maxRadius );
}

unsigned int Sampler::getYRes( const CVGreyc::NDArray::CArray<double> &data ) const
{
	return data.shape(1) - ( 2*maxRadius );
}

unsigned int Sampler::nbSamples() const
{
	return pattern.size();
}

const char *Sampler::InvalidIndex::what() const throw()
{
	return "Index out of range";
}
